/* 
 @author   Ahmed Khudairy
 @contact  akhudairy@gmail.com
 @project  Mall Kit
 */
 
 package com.framework.utils
 {
 	import flash.display.Bitmap;
 	import flash.display.BitmapData;
 	import flash.display.DisplayObject;
 	import flash.geom.Point;
 	import flash.geom.Rectangle;
 	import flash.text.StyleSheet;
 	
 	import mx.core.Application;
 	import mx.core.Container;
 	import mx.core.UIComponent;
 	
 	/**
	 * All static methods that helps with operations related to User Inerface
	 * Components. These methods includes drawing copies of UI components, retrieving
	 * a reference to component(find), or get global position. 
	 */
 	public final class UIUtils extends AbstractStaticType
 	{
 		/**
		 * 
		 * @return The application container
		 * 
		 */		
		public static function getDocumentRoot() : Container
		{
			var documentRoot:Container = Application.application as Container;
			return documentRoot;
		}
		
		/**
	     * 
	     * @param context Any <code>DisplayObject</code>
	     * @return a new <code>Rectangle</code> represnting <code>DisplayObject</code> position
	     * in application, and has the <code>DisplayObject</code> width and height.
	     * 
	     */		
	    public static function getGlobalBounds(context:DisplayObject) : Rectangle
	    {
	        var point:Point = new Point(0, 0);
	        point = context.localToGlobal( point );
	        
	        var rect:Rectangle = new Rectangle( point.x, point.y, context.width, context.height ); 
	        return rect;
	    }
	    
	    /**
	     * 
	     * @param context Any <code>DisplayObject</code>
	     * @return <code>Point</code> represnting <code>DisplayObject</code> position
	     * in application.
	     * 
	     */	   
	    public static function getLocalToGlobal(context:DisplayObject) : Point
	    {
	        var point:Point = new Point(0, 0);
	        point = context.localToGlobal( point );

	        return point;
	    }
	    
	     /**
	     * 
	     * @param context Any <code>DisplayObject</code>
	     * @param container Any <code>DisplayObject</code>
	     * @return a <code>Rectangle</code> representing <code>context</code> x,y,width and height
	     * relative to <code>container</code> object.
	     * 
	     */	   
	    public static function getRelativeCooridnates(context:DisplayObject, container:DisplayObject) : Rectangle
	    {
	    	var rect:Rectangle;
	    	
	    	if (context && container)
	    	{
	    		rect = context.getRect(container);
	    	}
	    	else
	    	{
	    		rect = new Rectangle();
	    	}
	    	
	    	return rect;
	    }
	    
	    /**
		 * 
		 * @return <code>Rectangle</code> representing application screen
		 * 
		 */	    
		public static function getScreen() : Rectangle
		{
			var documentRoot:Container = Application.application as Container;
			var rect:Rectangle = documentRoot.getBounds( documentRoot );
			return rect;
		}
		
		/**
		 * 
		 * @return application width
		 * 
		 */	
		public static function get screenWidth() : Number
		{
			return getScreen().width;
		}
		
		/**
		 * 
		 * @return application height
		 * 
		 */
		public static function get screenHeight() : Number
		{
			return getScreen().height;
		}
		
		/**
		 * 
		 * Used to add offsets to a <code>Rectangle</code>.
		 * 
		 * @param rect <code>Rectangle</code> which offsets will be summed to
		 * @param horizontalOffset is summed to <code>x</code> attribute of <code>Rectangle</code>
		 * @param verticalOffset is summed to <code>y</code> attribute of <code>Rectangle</code>
		 * @param widthOffset is summed to <code>width</code> attribute of <code>Rectangle</code>
		 * @param heightOffset is summed to <code>height</code> attribute of <code>Rectangle</code>
		 * 
		 * @return new Object of type <code>Rectangle</code> with attributes similar to
		 *  <code>rect</code> after offsets are calculated with it.
		 */
		public static function correctBounds(rect:Rectangle, horizontalOffset:Number, verticalOffset:Number, 
												widthOffset:Number, heightOffset:Number): Rectangle
		{
			var newRectangle:Rectangle = new Rectangle();
			newRectangle.x = rect.x + horizontalOffset;
			newRectangle.y = rect.y + verticalOffset;
			newRectangle.width = rect.width + widthOffset;
			newRectangle.height = rect.height + heightOffset;
			
			return newRectangle;
		}
		
		/**
	    * 
	    * This will search the application for the component that has a
	    * certain <code>name<code> or <code>id<code>. and returns the first
	    * one it finds. otherwise it returns null.
	    * 
	    * @param componentName <code>String</code> defining component name or id.
	    * 
	    * @return A refrence to the component found. returns null if not
	    * found.
	    * 
	    */
	    public static function getComponent(componentName:String):UIComponent
	    {
	    	//quick return
	    	if (componentName == "")
	    	{
	    		return null;
	    	}
	    	
	    	var mainApp:Container = getDocumentRoot();
	    	var appChildren:Array = mainApp.getChildren();
	    	return findComponent(componentName, appChildren);
	    }
	    
	    /**
	     * recursive function. That will loop through an array of components and
	     * their children components. and it stops if it finds a component with
	     * name or id equals to parameter <code>componentName</code>.
	     * 
	     * @param componentName <code>String</code> defining component name or id.
	     * @param compsArr Array of components to be searched.
	     * 
	     * @return A refrence to the component found. returns null if not
	     * found.
	     */
	    public static function findComponent(componentName:String, compsArr:Array):UIComponent
		{
			var obj:Object;
			var found:UIComponent;
			var i:int;
			var length:int = compsArr.length;
			var component:Object;
			
			for (i = 0; i < length ; i++)
			{
				component = compsArr[i];
				
				if (component.hasOwnProperty("name") && component.name == componentName)
				{
					 return component as UIComponent;
				}
				else if (component.hasOwnProperty("id") && component.id == componentName)
				{
					 return component as UIComponent;
				}
				else 
				{
					if (component.hasOwnProperty("getChildren") && component.getChildren().length > 0)
					{
						found = findComponent(componentName, component.getChildren());
						
						if (found && (found.name == componentName || found.id == componentName))
						{ 
							return found;
						}
					}	
				}
			}
			
			return found;
		}
		
		/**
		 * Returns a <code>Bitmap</code> copy for any UI component.
		 * 
		 * @param uiComponent <code>UIComponent</code> object
		 * 
		 * @return picture of type <code>Bitmap</code>, that looks exactly
		 * like the component send to object.
		 */
		public static function drawComponent(uiComponent:UIComponent) : Bitmap
		{
			var data : BitmapData = new BitmapData(uiComponent.width, uiComponent.height, true, 0);
			data.draw(uiComponent);
			var bitmap: Bitmap = new Bitmap(data);
			return bitmap;
		}
		
		/**
		 * Returns a style sheet to be used to set a hover state for text
		 * controls, where htmlText is used and there are links in text.
		 * you can use it to set <code>styleSheet</code> for <code>TextArea</code> 
		 * or <code>wwText</code>
		 * 
		 * @param underlined if true, links will be underlined.
		 * @return <code>StyleSheet</code>
		 * 
		 * @example following example shows how this can be used, on runtime
		 * 
		 * <listing version="3.0" >
		 * var bodyText:wwText = new wwText();
		 * bodyText.styleSheet = UIUtils.getALinkStyleSheet(true);
		 * </listing>
		 */
		public static function getALinkStyleSheet(underlined:Boolean = false) : StyleSheet
		{
	    	var anchor:Object = new Object();
	    	anchor.color = "#006699";
	        var hover:Object  = new Object();
	        hover.color = "#38A800";
	        
	        if (underlined)
	        {
	        	anchor.textDecoration = "underline";
	        	hover.textDecoration = "underline";
	        }
	        
	        var style:StyleSheet = new StyleSheet();
	        style.setStyle( "a",       anchor );
	        style.setStyle( "a:hover", hover  );
	        
	        return style;
		}
		
		/**
		 * @param component <code>UIComponent</code> object
		 * @return returns true if mouse is over component, and false otherwise
		 */
		public static function isMouseOver(component:UIComponent) : Boolean
		{
			if (component == null)
			{
				return false;
			}
			
			if (component.mouseX < 0 || component.mouseX > component.width)
			{
				return false;
			}
			
			if (component.mouseY < 0 || component.mouseY > component.height)
			{
				return false;
			}
			
			return true;
		}
 	}
 }